﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;


namespace XCommunity.Forums.Views
{
  public class Route
  {

    private static HashAlgorithm _hashAlgorithm = new HMACMD5( Encoding.GetBytes( "fdhsADwSa^&#GYui3ghu" ) );


    private string[] _nodes;

    protected Route( string[] nodes )
    {
      _nodes = nodes;
    }


    private byte[] _encrypt;

    protected byte[] EncryptRoute
    {
      get
      {
        if ( _encrypt == null )
          _encrypt = Encrypt( RouteString );

        return _encrypt;

      }
    }



    public Route AppendNode( string node )
    {
      var new_nodes = new string[Nodes.Length + 1];
      Nodes.CopyTo( new_nodes, 0 );
      new_nodes[Nodes.Length] = node;

      return new Route( new_nodes );
    }


    public string[] Nodes
    {
      get { return _nodes; }
    }


    public string LastNode
    {
      get { return Nodes.Last(); }
    }



    public Route Parent
    {
      get
      {
        if ( Nodes.Length == 1 )
          return null;


        var new_nodes = new string[Nodes.Length - 1];
        Array.Copy( Nodes, new_nodes, Nodes.Length - 1 );

        return new Route( new_nodes );
      }
    }


    public string RouteString
    {
      get { return string.Join( "/", Nodes ); }
    }









    protected static Encoding Encoding
    {
      get { return Encoding.UTF8; }
    }


    protected static byte[] Encrypt( string route )
    {
      byte[] routeBytes = Encoding.GetBytes( route );
      byte[] hashBytes = _hashAlgorithm.ComputeHash( routeBytes );

      byte[] result = new byte[routeBytes.Length + hashBytes.Length];

      hashBytes.CopyTo( result, 0 );
      routeBytes.CopyTo( result, _hashAlgorithm.HashSize / 8 );

      return result;
    }

    protected static string Decrypt( byte[] encryptRoute )
    {
      int hashSize = _hashAlgorithm.HashSize / 8;
      byte[] hashBytes = new byte[hashSize];
      byte[] routeBytes = new byte[encryptRoute.Length - hashSize];

      Array.Copy( encryptRoute, hashBytes, hashSize );
      Array.Copy( encryptRoute, hashSize, routeBytes, 0, routeBytes.Length );

      byte[] _hashBytes = _hashAlgorithm.ComputeHash( routeBytes );
      if ( !_hashBytes.SequenceEqual( hashBytes ) )
        return null;

      return Encoding.GetString( routeBytes );
    }



    public override string ToString()
    {
      return Convert.ToBase64String( EncryptRoute ).Replace( '+', '(' ).Replace( '/', '-' ).Replace( '=', ')' );
    }

    public static Route DescyptRoute( string encryptString )
    {
      var data = Convert.FromBase64String( encryptString.Replace( '(', '+' ).Replace( '-', '/' ).Replace( ')', '=' ) );

      var route = Decrypt( data );

      if ( route == null )
        throw new InvalidOperationException( "解密路由信息失败" );//UNDONE 强类型异常


      return new Route( route.Split( '/' ) );
    }



    public static Route operator +( Route route, string node )
    {
      return route.AppendNode( node );
    }
  }
}
